home *** CD-ROM | disk | FTP | other *** search
- page 60,132
- .lfcond
- title "TRACE - Interrupt Tracer"
- subttl Introduction
- page
- comment \
-
- TRACE is an INT tracer. It traps INT's, traces the registers at the entry
- to the INT, executes the INT itself, and then traces the regs at exit from
- the INT. It also allows the user at the keyboard to see all of this traced
- information, either at the screen or on the printer.
-
- The INT's that are to be traced are specified in the source code (see config
- section below). Once defined, they may be enabled or disabled from the
- keyboard.
-
- <<< REBOOT AS SOON AS POSSIBLE AFTER INVOKING TRACE!!! >>>
-
- This is not foolproof or bugfree. We use it 'cause it's a terrific tool
- for deprotecting copy-protected software. You use it at your own risk.
- When you've gotten a printout of the trace activity that interests you,
- reboot your system. Don't say that we didn't warn you.
-
- Enjoy.
-
- \
- page
- code segment para 'code'
- assume cs:code,ds:code
- org 0100h
- start: jmp init
-
- ;********************************************************
- ;
- ; Definition of one interrupt control table
- ;
- ;********************************************************
-
- ICT struc
- ICT_flags db ? ;See below
- ICT_intnum db ? ;interrupt # this table belongs to
- ICT_AH_lo db ? ;lower AH limit to trace
- ICT_AH_hi db ? ;upper AH limit to trace
- ICT_orig_hndlr dd ? ;cs:ip of original handler
- ICT_hits dw ? ;# traces made for this ICT
- ICT_num db ? ;ICT number (0-7)
- ICT ends
-
- ;
- ; Equates for flags byte of ICT
- ;
-
- F_ACTIVE equ 10000000b ;Bit 7 = this ICT is active
- F_RET equ 01000000b ;Bit 6 = This INT exits via RET
- F_RET2 equ 00100000b ;Bit 5 = This INT exits via RET2
- F_IRET equ 00010000b ;Bit 4 = This INT exits via IRET
- F_ENABLE equ 00001000b ;Bit 3 = Tracing enabled for this ICT
- F_FCB equ 00000100b ;Bit 2 = enable FCB/ASCII traces for INT 21h
- F_ROM equ 00000010b ;Bit 1 = exclude ROM invocations of this INT
- F_BELOW equ 00000001b ;Bit 0 = exclude invokers below us (DOS etc)
-
- page
- ;*******************************************************
- ; B E G I N C O N F I G U R A T I O N
- ;*******************************************************
-
- ;
- ; Set trace_size to number of bytes to set aside for trace table.
- ;
-
- trace_size equ 30000
-
- ;
- ; Set peri_int to the interrupt number (usually 060H) to be used
- ; by Periscope to invoke our reporting routines.
- ;
-
- peri_int equ 060h
-
- ;
- ; Set prt_scr non-zero to assemble code that allows control via SHIFT-PrtSc.
- ;
-
- prt_scr equ 1
-
- ;
- ; Set use_prt non-zero to start up using the printer instead of the screen
- ;
-
- use_prt equ 0
-
- ;
- ; Set num_feeds to number of extra Linefeeds to send to printer to jack
- ; up the paper enough to let you read it, after display of menus etc.
- ;
-
- num_feeds equ 10
-
-
- ;
- ; Define interrupts to be traced by filling in the following ICT's.
- ; Note that there are only 8. That's the max that can be traced.
- ; Note that the F_ACTIVE flag must be set in used ICT's, and off in
- ; those that aren't defining something that you want traced.
- ;
- ; Don't mess with the last 3 fields in the ICT!!! Leave 'em as-is.
- ;
- ; It is EXTREMELY important that you specify how the interrupt exits.
- ; Set exactly one of the following flag bits:
- ;
- ; F_RET Interrupt exits via simple far RET, leaving original interrupts
- ; on the stack for the caller to pop. INT's 025H and 026H are prime
- ; examples.
- ;
- ; F_RET2 Interrupt exits via RET 2, dropping original flags and returning
- ; flags as set by interrupt handler. INT 021H (and anybody else
- ; that uses flags like CARRY or ZERO to reflect results) does this.
- ;
- ; F_IRET Interrupt exits via IRET, restoring original flags from stack.
- ; Hardware interrupt handlers do this, and many ROM BIOS routines.
- ;
- ; Note that some interrupts may exit differently, depending on the specific
- ; function requested. You may want to define several ICT's for a given
- ; interrupt, each handling a different AH range.
- ;
- ;
-
- ict0 ICT <F_ACTIVE+F_RET2+F_ENABLE+F_FCB,021H,0dh,0ffh,0,0,0> ;DOS funcs 0Dh thru FFh
- ict1 ICT <F_ACTIVE+F_RET2+F_ENABLE,013H,0,0ffh,0,0,1> ;ROM BIOS INT 13h (all)
- ict2 ICT <F_ACTIVE+F_RET2,021H,0,0ch,0,0,2> ;DOS funcs 00h thru 0Ch
- ict3 ICT <F_ACTIVE+F_RET+F_ENABLE,025h,0,0ffh,0,0,3> ;RAW disk I/O
- ict4 ICT <F_ACTIVE+F_RET+F_ENABLE,026h,0,0ffh,0,0,4> ;RAW disk I/O
- ict5 ICT <0,0,0,0,0,0,5> ;unused
- ict6 ICT <0,0,0,0,0,0,6> ;unused
- ict7 ICT <0,0,0,0,0,0,7> ;unused
-
-
- ;*******************************************************
- ; E N D C O N F I G U R A T I O N
- ;*******************************************************
- page
- ;
- ; Trace entry byte zero (the type byte) identifies entry as follows:
- ;
- ; Bits 7-4 = trace type
- ;
- ; 0000 = BEFORE int was executed
- ; 0001 = AFTER int was executed
- ; 0010 = FCB referenced by an INT 21h
- ; 0011 = ASCIIZ referenced by an INT 21h
- ;
- ; Bit 3 = RESERVED
- ;
- ; Bits 2-0 = ICT # (0-7) which made this trace record
- ;
- ; Record formats are as follows:
- ;
-
- BEFORE struc ;BEFORE trace entry
- B_type db ? ;see above
- B_int db ? ;INT # that was trapped
- B_ax dw ? ;Regs BEFORE executing INT
- B_bx dw ?
- B_cx dw ?
- B_dx dw ?
- B_es dw ?
- B_ds dw ?
- B_ss dw ?
- B_sp dw ?
- B_si dw ?
- B_di dw ?
- B_bp dw ?
- B_cs dw ? ;CS of invoker of INT
- B_ip dw ? ;IP of invoker
- BEFORE ends
-
- AFTER struc ;AFTER record type
- A_type db ? ;see above
- A_int db ? ;INT # that was executed
- A_ax dw ? ;Regs AFTER executing INT
- A_bx dw ?
- A_cx dw ?
- A_dx dw ?
- A_es dw ?
- A_ds dw ?
- A_si dw ?
- A_di dw ?
- A_bp dw ?
- A_flags dw ? ;Flags AFTER doing INT
- AFTER ends
-
- FCB struc ;INT 21h FCB record
- FCB_type db ? ;see above
- FCB_int db ? ;INT # that was executed (21h)
- FCB_drive db ? ;drive field of FCB
- FCB_name db "????????" ;filename field of FCB
- FCB_ext db "???" ;extension field of FCB
- FCB ends
-
- ASCIIZ struc ;INT 21h ASCIIZ record
- AZ_type db ? ;see above
- AZ_int db ? ;INT # that was executed (21h)
- AZ_str db "?????????????????????????????????????????????????????????????????"
- ASCIIZ ends
-
- subttl Resident Storage
- page
-
- ;
- ; Things defined here are present even after we become resident and
- ; exit to DOS.
- ;
-
- ;
- ; Definitions used by print_edit()
- ;
-
- Edit_End equ 0f0h ;End of input line
- Edit_Byte equ 0f1h ;Next byte is 8-bit value to be printed in hex
- Edit_Word equ 0f2h ;Next 2 bytes are 16-bit value to be printed in hex
- Edit_Line equ 0f3h ;Next 2 bytes are address of string for print_line()
- Edit_Call equ 0f4h ;Next byte is AH arg, next 2 are DX arg,
- ;and next 2 are subroutine address to call
- Edit_Dec8 equ 0f5h ;Next byte is 8-bit value to be printed as decimal
- Edit_Dec16 equ 0f6h ;Next 2 bytes are 16-bit value to be printed as decimal
- Edit_Skip equ 0f7h ;Ignore this byte (don't display it)
-
- ;********************************************************
- ;
- ; Index table pointing to all ICT's
- ;
- ;********************************************************
-
- ict_index label word
- dw offset ict0
- dw offset ict1
- dw offset ict2
- dw offset ict3
- dw offset ict4
- dw offset ict5
- dw offset ict6
- dw offset ict7
-
- ;********************************************************
- ;
- ; Index table pointing to all handlers
- ;
- ;********************************************************
-
- hndlr_index label word
- dw offset handler0
- dw offset handler1
- dw offset handler2
- dw offset handler3
- dw offset handler4
- dw offset handler5
- dw offset handler6
- dw offset handler7
-
- ;********************************************************
- ;
- ; Trace table itself, with plenty of room
- ;
- ;********************************************************
-
- next_byte dw offset trace_table ;address of next entry
-
- trace_table db trace_size dup (0)
-
- last_byte db 80 dup (0) ;sloppy way of handling overflow
-
- ;********************************************************
- ;
- ; Table of sizes for each trace record type. Must be in same
- ; order as record types themselves.
- ;
- ;********************************************************
-
- rec_sizes label word
- dw size BEFORE
- dw size AFTER
- dw size FCB
- dw size ASCIIZ
-
- ;********************************************************
- ;
- ; Table of INT 21h functions that include an FCB pointer in DS:DX
- ;
- ;********************************************************
-
- FCB_table label byte
- db 0fh,10h,11h,12h,13h,14h,15h,16h,17h,21h,22h,23h,24h,27h,28h
- FCB_end label byte
-
-
- ;********************************************************
- ;
- ; Table of INT 21h functions that include an ASCIIZ pointer in DS:DX
- ;
- ;********************************************************
-
- ASCIIZ_table label byte
- db 4bh,3ch,3dh,41h,43h,4eh,56h,5ah,5bh,39h,3ah,3bh
- ASCIIZ_end label byte
-
- ;********************************************************
- ;
- ; Misc storage
- ;
- ;********************************************************
-
- our_cs dw 0 ;our CS (not for segment checking)
- test_cs dw 0 ;our normalized CS (for segment checking)
- long_addr dd 0 ;for long JMP's and CALLs
- our_ICT dw 0 ;for quick save of our ICT pointer
- our_flags db 0 ;for quick save of our ICT flags
- prt_base dw 0 ;base I/O address of printer
- prt_flag db 0 ;non-zero to send output to printer
- db 255 dup (0) ;stack for Periscope Int handler
- our_tos dw 0 ;top of that stack
- stack_inuse db 0 ;non-zero when above stack is in use
- save_ss dw 0 ;for stack-swapping
- save_sp dw 0
-
-
- subttl Interrupt Trappers and Tracing
- page
-
- ;********************************************************
- ;
- ; Interrupt handler entry points for each ICT
- ;
- ;********************************************************
-
- handler macro ictloc
- cli ;*** NO INTERRUPTS!!! ***
- push bp ;save stack pointer, so that...
- mov bp,sp ;...we can ref things via BP
- push bx ;set BX to point to ICT
- mov bx,offset cs:ictloc
- jmp short int_common ;goto common code
- endm
-
- interrupt proc far
-
- handler0:
- handler ict0
-
- handler1:
- handler ict1
-
- handler2:
- handler ict2
-
- handler3:
- handler ict3
-
- handler4:
- handler ict4
-
- handler5:
- handler ict5
-
- handler6:
- handler ict6
-
- handler7:
- handler ict7
-
-
- int_common:
-
- push ax
-
- ;********************************************************
- ;
- ; Common code for all trapped INT's.
- ;
- ; At this point:
- ;
- ; BX holds ICT address.
- ; BP points to stack as follows:
- ;
- ; AX
- ; BX
- ; (BP) ----> BP
- ; +2 IP of caller
- ; +4 CS of caller
- ; +6 FLAGS of caller
- ;
- ;********************************************************
-
- test cs:[bx].ICT_flags,F_ENABLE ;tracing enabled for this ICT?
- jz no_trace ;no, don't trace it
- cmp ah,cs:[bx].ICT_AH_lo ;is AH within bounds?
- jb no_trace ;no, don't trace it
- cmp ah,cs:[bx].ICT_AH_hi
- ja no_trace ;no, don't trace it
-
- ;
- ; See if we should check caller's CS:IP
- ;
-
- test cs:[bx].ICT_flags,F_BELOW+F_ROM
-
- jz int_common3 ;no segment checks to be made
- mov ax,2[bp] ;get caller's IP
- shr ax,1 ;prepare to normalize segment #
- shr ax,1
- shr ax,1
- shr ax,1
- add ax,4[bp] ;add in segment
-
- ;
- ; ------ AX now equals normalized segment #
- ;
-
- test cs:[bx].ICT_flags,F_BELOW
-
- jz int_common2 ;don't check for invoker below us
- cmp ax,cs:test_cs ;is caller below us?
- jb no_trace ;yes, don't trace
-
- int_common2:
-
- test cs:[bx].ICT_flags,F_ROM
-
- jz int_common3 ;don't check for invoker in ROM
- cmp ax,0c000h ;is caller in ROM?
- jae no_trace ;yes, don't trace
-
- int_common3:
-
- ;
- ; See if we have room for this trace
- ;
-
- mov ax,cs:next_byte ;get address of next entry
- push ax
- add ax,size BEFORE ;add size of this record
- cmp ax,offset cs:last_byte ;would record fit?
- pop ax
- jb yes_trace ;yes, there's room
-
- no_trace:
-
- ;
- ; We are not to trace this INT, for whatever reason.
- ; Just go to original handler, and return to caller (not to us).
- ;
-
- mov ax,word ptr cs:[bx].ICT_orig_hndlr
- mov word ptr cs:long_addr,ax
- mov ax,word ptr cs:[bx].ICT_orig_hndlr+2
- mov word ptr cs:long_addr+2,ax
- pop ax
- pop bx
- pop bp
- jmp cs:long_addr ;let original handler return to caller
-
-
- yes_trace:
-
- ;
- ; We are to proceed with trace of this INT. Make trace entry.
- ;
-
- push es
- push di
-
- ;
- ; At this point:
- ;
- ; AX holds offset to next trace entry.
- ; BX holds ICT address.
- ; BP points to stack as follows:
- ;
- ; DI
- ; ES
- ; AX
- ; BX
- ; (BP) ----> BP
- ; +2 IP of caller
- ; +4 CS of caller
- ; +6 FLAGS of caller
- ;
-
- mov di,ax ;set ES:DI to next trace entry
- mov ax,cs
- mov es,ax
- cld ;forward!!!
- mov ah,cs:[bx].ICT_intnum ;get interrupt # being traced
- mov al,cs:[bx].ICT_num ;get ICT #, make BEFORE record type
- stosw
- mov ax,-4[bp] ;original AX
- stosw
- mov ax,-2[bp] ;original BX
- stosw
- mov ax,cx
- stosw
- mov ax,dx
- stosw
- mov ax,-6[bp] ;original ES
- stosw
- mov ax,ds
- stosw
- mov ax,ss
- stosw
- mov ax,bp ;original SP
- add ax,2
- stosw
- mov ax,si
- stosw
- mov ax,-8[bp] ;original DI
- stosw
- mov ax,[bp] ;original BP
- stosw
- mov ax,4[bp] ;caller's CS
- stosw
- mov ax,2[bp] ;caller's IP
- stosw
-
- mov cs:next_byte,di ;save spot for next trace entry
- inc cs:[bx].ICT_hits ;bump number of traces made for this ICT
-
- ;
- ; We're done with the BEFORE trace. See if we are to do an FCB or ASCIIZ
- ; trace record.
- ;
-
- test cs:[bx].ICT_flags,F_FCB
- jz no_FCB ;no, we are definitely not supposed to
- cmp cs:[BX].ICT_intnum,021h ;is this an INT 21h?
- jnz no_FCB ;no, can't trace it then
-
- ;
- ; Search through ASCIIZ function table, to see if function that was called
- ; is one that contains an ASCIIZ pointer in DS:DX
- ;
-
- mov ax,-4[bp] ;get AX at time of call
- push cx
- mov di,offset cs:ASCIIZ_table
- mov cx,offset cs:ASCIIZ_end
- sub cx,di ;CX now has size of table
- mov al,ah ;get function to AL
- repnz scasb ;see if it's in table
- pop cx
- jz trace_ASCIIZ ;it's there, so do ASCIIZ trace
-
- ;
- ; Search through FCB function table, to see if function that was called
- ; is one that contains an FCB pointer in DS:DX
- ;
-
- push cx
- mov di,offset cs:FCB_table
- mov cx,offset cs:FCB_end
- sub cx,di ;CX now has size of table
- repnz scasb ;see if it's in table
- pop cx
- jnz no_FCB ;no FCB or ASCIIZ trace called for
-
- ;
- ; We are to do trace of FCB pointed to by DS:DX
- ;
-
- mov al,00100000b ;trace record number for FCB trace
- mov ah,size FCB ;size of record
- jmp short trace_common ;rest is common code
-
- trace_ASCIIZ:
-
- ;
- ; We are to do trace of ASCIIZ string pointed to by DS:DX
- ;
-
- mov al,00110000b ;trace record number for ASCIIZ trace
- mov ah,size ASCIIZ ;size of record
-
- trace_common:
-
- ;
- ; Copy bytes from DS:DX to new ASCIIZ or FCB trace record.
- ;
- ; At this point:
- ;
- ; AL holds trace record type, properly positioned in bits 7-4
- ; AH holds size of record that we're doing (the full record)
- ;
-
- sub ah,2 ;minus two bytes for record header
- mov di,cs:next_byte ;see if there's room...
- push di
- push ax
- mov al,ah ;get record size to AX
- xor ah,ah
- add di,ax
- cmp di,offset cs:last_byte
- pop ax
- pop di
- jae no_FCB ;no room
- push ax ;save AX over this
- mov ah,cs:[bx].ICT_intnum ;start header with interrupt #
- or al,cs:[bx].ICT_num ;add ICT number to trace type
- stosw ;start new record with it
- pop ax ;restore AX
- push cx
- push si
- mov si,dx ;access DS:DX as DS:SI
- mov cl,ah ;record size to CX
- xor ch,ch
- rep movsb ;that's how many to copy
- pop si
- pop cx
- mov cs:next_byte,di ;save offset to next record
-
- no_FCB: ;end of FCB/ASCIIZ tracing
-
-
- ;
- ; Having traced all of those, now invoke original interrupt handler. Have
- ; it return to us, not the original caller of the interrupt.
- ;
-
- mov cs:our_ICT,bx ;save ICT pointer for a nanosecond
- mov al,cs:[bx].ICT_flags ;save copy of flags that we can get to
- mov cs:our_flags,al
-
- mov ax,word ptr cs:[bx].ICT_orig_hndlr
- mov word ptr cs:long_addr,ax
- mov ax,word ptr cs:[bx].ICT_orig_hndlr+2
- mov word ptr cs:long_addr+2,ax
-
- pop di
- pop es
- pop ax
- pop bx
- pop bp
- push cs:our_ICT ;save ICT pointer on stack
- test cs:our_flags,F_RET ;should we push flags?
- jnz no_flags ;no, cause they'd be left on stack
- pushf ;yes, give handler some flags to drop
-
- no_flags:
- call cs:long_addr ;invoke original handler
-
-
- ;
- ; We're back from the real interrupt handler, and can make the "after" trace.
- ; Our ICT address is on stack.
- ;
-
- sti ;give world a crack at interrupts
- nop
- nop
- cli ;*** NO INTERRUPTS!!! ***
- push bp ;establish stack reference
- mov bp,sp
- pushf ;save resultant flags
- push es
- push di
- push ax
- push bx
-
- ;
- ; At this point:
- ;
- ; BX
- ; AX
- ; DI
- ; ES
- ; FLAGS (as returned by real interrupt)
- ; (BP) --------> BP
- ; ICT address
- ; IP of caller
- ; CS of caller
- ; FLAGS of original caller
- ;
-
- mov bx,2[bp] ;recover ICT address
- mov di,cs:next_byte ;room for "after" trace entry?
- push di
- add di,size AFTER
- cmp di,offset cs:last_byte
- pop di
- jae no_after ;no, skip it
- mov ax,cs ;make ES:DI point to next entry
- mov es,ax
- cld ;forward!!!
- mov ah,cs:[bx].ICT_intnum ;get interrupt #
- mov al,cs:[bx].ICT_num ;get ICT #, make AFTER record type
- or al,00010000b
- stosw
- mov ax,-8[bp] ;AX at int's return
- stosw
- mov ax,-10[bp] ;BX at int's return
- stosw
- mov ax,cx
- stosw
- mov ax,dx
- stosw
- mov ax,-4[bp] ;ES at int's return
- stosw
- mov ax,ds
- stosw
- mov ax,si
- stosw
- mov ax,-6[bp] ;DI at int's return
- stosw
- mov ax,[bp] ;BP at int's return
- stosw
- mov ax,-2[bp] ;FLAGS at int's return
- stosw
-
- mov cs:next_byte,di ;save offset to next entry
-
- no_after:
-
- ;
- ; All done making "after" trace, or we've skipped it cause there was
- ; no room for it.
- ;
- ; Now just exit back to the original caller.
- ;
-
- mov al,cs:[bx].ICT_flags ;save flags where we can get to them
- mov cs:our_flags,al
- pop bx
- pop ax
- pop di
- pop es
- popf
- pop bp
- pop cs:our_ICT ;drop ICT address without affecting flags
-
- ;
- ; HOW we exit is extremely important. We must exit the same way that the
- ; real interrupt does.
- ;
-
- pushf ;save current flags in case we return them
- test cs:our_flags,F_RET
- jnz exit_ret
- test cs:our_flags,F_RET2
- jnz exit_ret2
-
- ;
- ; Assume IRET.
- ;
-
- exit_iret:
- popf ;exit via IRET, reloading original flags
- STI ;Allow interrupts now
- iret
-
- exit_ret2:
- popf ;exit via RET 2, discarding original flags
- STI ;Allow interrupts now
- ret 2
-
- exit_ret:
- popf ;exit via far RET, leaving original flags
- STI ;Allow interrupts now
- ret
-
- interrupt endp
-
- subttl Support routines - Printer & Screen I/O
- page
- ;*****************************************
- ;
- ; Select video for subsequent output
- ;
- ;*****************************************
-
- selvideo proc near
- mov prt_flag,0
- ret
- selvideo endp
-
-
- ;*****************************************
- ;
- ; Select printer for subsequent output
- ;
- ;*****************************************
-
- selprint proc near
- push ax
- mov ax,prt_base ;do we have a printer?
- or al,ah
- mov prt_flag,al ;al is non-zero if we do
- pop ax
- ret
- selprint endp
-
- ;********************************************************
- ;
- ; Output AL to printer or screen, depending on prt_flag.
- ;
- ;********************************************************
-
- print proc near
- push dx
- push cx
- push bx
- push ax
-
- ; ----- See if it should go to printer
-
- test prt_flag,0ffh ;send it to printer?
- jnz print1 ;yes
-
- print0:
-
- ;
- ; Send char to video via INT 010H
- ;
-
- mov bl,1
- mov ah,14 ;"Write TTY" func
- int 010h
- clc ;show no I/O error
- jmp short print9
-
- print1:
-
- ;----- Send it to printer
-
- mov dx,prt_base ;get printer base I/O address
- inc dx ;up to status port
- mov ah,al ;save char in ah
- xor cx,cx ;init timeout ticker
-
- print2:
- in al,dx ;get status
- test al,080h ;is printer busy?
- jnz print5 ;no, proceed to send char
-
- ;
- ; We're not immediately ready. Some printers require more of a wait than
- ; the simple 64K loop found in CX. So here's a time waster that you may
- ; want to tailor to your printer.
- ;
-
- mov al,8 ;greatly extend timeout value
-
- print3:
- dec al
- jnz print3
-
- loop print2 ;wait for whole timeout
- stc ;set carry for timeout
- jmp short print9 ;and exit
-
- print5:
- dec dx ;down to data reg
- mov al,ah ;recover char to be sent
- out dx,al ;put it on data lines
- inc dx ;up to control port
- inc dx
- mov al,0dh ;set strobe low
- out dx,al
- mov al,0ch ;set strobe high again
- out dx,al
- clc ;show no error
-
- print9:
-
- ;
- ; At this point, CARRY is SET if we were going to the printer and had an
- ; I/O error.
- ;
-
- jnc print10 ;no error
- call selvideo ;error, so switch to video
- pop ax ;recover AL
- push ax
- jmp print0 ;go send it to video
-
- print10:
- pop ax
- pop bx
- pop cx
- pop dx
- ret
- print endp
-
- ;********************************************************
- ;
- ; Output binary AL as 2 hex digits
- ;
- ;********************************************************
-
- print_hex proc near
- push bx
- push ax
- mov bl,al ;isolate HO nibble
- shr bl,1
- shr bl,1
- shr bl,1
- shr bl,1
- and bx,0fh
- mov al,hextab[bx] ;xlit to hex char
- call print ;print 1st char
- pop ax
- push ax
- mov bl,al ;isolate LO nibble
- and bx,0fh
- mov al,hextab[bx] ;xlit to hex char
- call print ;print 2nd char
- pop ax
- pop bx
- ret
- print_hex endp
-
- hextab db '0123456789ABCDEF'
-
- ;********************************************************
- ;
- ; Output binary word AX as 4 hex digits
- ;
- ;********************************************************
-
- print_word proc near
- xchg ah,al ;get HO half to AL
- call print_hex ;print 1st 2 chars
- xchg ah,al ;get LO half back to AL
- call print_hex ;print 2nd 2 chars
- ret
- print_word endp
-
- ;********************************************************
- ;
- ; Output binary word AX as 4 hex digits, plus a blank
- ;
- ;********************************************************
-
- print_wordb proc near
- push ax
- call print_word
- mov al,' '
- call print
- pop ax
- ret
- print_wordb endp
-
- ;*****************************************
- ;
- ; Print CRLF.
- ;
- ;*****************************************
-
- crlf proc near
- push ax
- mov al,0dh
- call print
- mov al,0ah
- call print
- pop ax
- ret
- crlf endp
-
- ;*****************************************
- ;
- ; Print string at DS:DX, up to "$" character.
- ;
- ;*****************************************
-
- print_line proc near
- push si
- push ax
- cld ;forward!
- mov si,dx ;DS:SI = string
-
- print_line2:
- lodsb ;get next byte to print
- cmp al,'$' ;terminating char?
- jz print_line9 ;yes, exit
- call print ;print this char
- jmp print_line2 ;continue till "$"
-
- print_line9:
- pop ax
- pop si
- ret
- print_line endp
-
- ;*****************************************
- ;
- ; Print DX (HO), AX (LO) as xxxx:xxxx.
- ;
- ;*****************************************
-
- print_seg proc near
- push ax
- mov ax,dx ;get HO word first
- call print_word
- mov al,':' ;show seperator too
- call print
- pop ax ;recover LO word
- call print_word
- ret
- print_seg endp
-
- ;********************************************************************
- ;
- ; Print a line at [DX], edited.
- ;
- ; Line may contain Edit_xxxx escape characters, as defined above.
- ;
- ;********************************************************************
-
- print_edit proc near
- push si
- push dx
- push cx
- push bx
- push ax
- mov si,dx ;use DS:SI to read line
- cld ;forward!!!
-
- print_edit2:
- lodsb ;get next byte of line
- cmp al,Edit_Byte ;binary byte to expand?
- jnz print_edit3 ;no
- lodsb ;yes, get 8-bit value
- call print_hex ;print it as hex
-
- print_edit2b:
- mov al,'H' ;tack "H" for HEX after it
-
- print_edit2c:
- call print
- jmp print_edit2 ;go get next char
-
- print_edit3:
- cmp al,Edit_Word ;16-bit binary to expand?
- jnz print_edit4 ;no
- lodsw ;yes, get 16-bit word
- call print_word ;display as hex
- jmp print_edit2b ;follow with 'H' and continue
-
- print_edit4:
- cmp al,Edit_Call ;call another routine?
- jnz print_edit5 ;no
- lodsb ;yes, get AH argument
- mov bh,al ;save for a nano...
- lodsw ;get DX argument
- mov dx,ax
- lodsw ;get address to call
- mov cx,ax
- mov ah,bh ;recover AH argument to use
- push si ;save our precious SI
- call cx ;call the routine
- pop si
- jmp print_edit2 ;go get next char
-
- print_edit5:
- cmp al,Edit_Dec8 ;8-bit decimal value?
- jnz print_edit6 ;no
- lodsb ;yes, get 8-bit byte
- xor ah,ah ;clear HO byte
-
- print_edit5b:
- call print_dec ;print AX as decimal
- jmp print_edit2 ;go get next input char
-
- print_edit6:
- cmp al,Edit_Dec16 ;16-bit decimal value?
- jnz print_edit7 ;no
- lodsw ;yes, get 16-bit byte
- jmp print_edit5b ;print it and go get next char
-
- print_edit7:
- cmp al,Edit_End ;end of input string?
- jnz print_edit2c ;no, assume ASCII char and print it
-
- pop ax
- pop bx
- pop cx
- pop dx
- pop si
- ret
- print_edit endp
-
-
- ;**************************************************
- ;
- ; Print AX in decimal, suppressing leading zeroes
- ;
- ;**************************************************
-
- print_dec proc near
- push dx
- push cx
- push bx
- push ax
- mov cx,10 ;divisor
- xor dx,dx
- div cx ;DL=units, AX = answer
- mov bh,dl ;save units
- xor dx,dx
- div cx ;DL=tens, AX = answer
- mov bl,dl ;get tens
- or bx,03030h ;make into 2 ASCII digits
- mov word ptr dec_buf+3,bx
- div cl ;AH=hunds, AL = answer
- mov bh,ah ;save hundreds
- xor ah,ah
- div cl ;AH=thous, AL = ten_thousands
- mov bl,ah ;get thous
- or bx,03030h ;make into 2 ASCII digits
- mov word ptr dec_buf+1,bx
- or al,030h ;make ten-thousands into ASCII digit
- mov byte ptr dec_buf,al
-
- ;
- ; Now edit out leading zeroes by advancing BX to 1st non-zero
- ;
-
- mov bx,offset dec_buf
- mov cx,4 ;max # to suppress
-
- print_dec2:
- cmp byte ptr [bx],'0'
- jnz print_dec5 ;found non-zero, so exit
- inc bx ;up to next digit
- loop print_dec2
-
- print_dec5:
-
- ;
- ; All set. Print from [BX] on...
- ;
-
- mov dx,bx
- call print_line
- pop ax
- pop bx
- pop cx
- pop dx
- ret
- print_dec endp
-
- dec_buf db "99999$"
-
-
- ;********************************************************************
- ;
- ; Print one string from a table of possible strings.
- ;
- ; On entry: AH holds selector
- ; DX holds table address
- ;
- ; Each table entry is as follows:
- ;
- ; db <selector>,"string",<term>
- ;
- ; where:
- ; <selector> is 8-bit byte that is compared with AH. If it
- ; matches, then this string is printed.
- ;
- ; "string" is the string to be printed
- ;
- ; <term> is the terminating character, as follows:
- ;
- ; 00H : end of this string
- ; 80H : end of this string, and end of table too
- ;
- ; If no <selector> matches AH, then "????" is printed.
- ;
- ;********************************************************************
-
- table_print proc near
- push si
- push dx
- push cx
- push bx
- push ax
- mov si,dx ;use DS:SI to read table
- cld ;forward!!!
-
- table_print2:
- lodsb ;get next selector
- cmp al,ah ;does it match AH?
- jnz table_print5 ;no, skip to next one
-
- table_print3:
-
- ;
- ; We have found string to print. Output it until a terminator is found.
- ;
-
- lodsb ;get byte of string
- test al,07fh ;terminator?
- jz table_print9 ;yes, exit
- call print ;no, print this char
- jmp table_print3
-
- table_print5:
-
- ;
- ; Not this selector. Skip over string till terminator, then go peek
- ; at next selector.
- ;
-
- lodsb ;get byte of string
- test al,07fh ;terminator?
- jnz table_print5 ;no, keep skipping
-
- ;
- ; We have terminator at end of skipped string. It may be end of whole table...
- ;
-
- cmp al,080h ;end of table?
- jnz table_print2 ;no, go check next selector
- mov dx,offset huh ;yes, print "????" message cause match not found
- call print_line
-
- table_print9:
- pop ax
- pop bx
- pop cx
- pop dx
- pop si
- ret
- table_print endp
-
- huh db "????$"
-
- ;*********************************************
- ;
- ; Issue extra linefeeds if we're going to the printer. This
- ; moves the paper up enough to be read.
- ;
- ; This should be called before any input, and whenever output is
- ; generally finished.
- ;
- ;*********************************************
-
- feed proc near
- push ax
- push cx
- test prt_flag,0ffh ;are we going to the printer?
- jz feed9 ;no, just exit
- mov cx,num_feeds ;# linefeeds to do
- jcxz feed9 ;none, so exit
-
- feed2:
- call crlf
- loop feed2
-
- feed9:
- pop cx
- pop ax
- ret
- feed endp
-
- subttl Menu Handling
- page
- ;*********************************************
- ;
- ; Get uppercase keyboard char to AL. AH is clobbered.
- ;
- ;*********************************************
-
- key proc near
- mov ah,0 ;use ROM BIOS to read keyboard
- int 016h
- cmp al,'a' ;lowercase char?
- jb key9 ;no
- cmp al,'z'
- ja key9 ;likewise no
- and al,0dfh ;yes, convert to uppercase
- key9:
- ret
- key endp
-
-
- ;*********************************************
- ;
- ; Reset all ICT hits to zero, and restart trace buffer
- ;
- ;*********************************************
-
- zap_hits proc near
- push si
- push ax
- push bx
- push cx
- mov cx,8 ;Number of ICT's
- xor si,si ;start with # 0
- cli ;no interrupts!
-
- zap_hits2:
- mov bx,ict_index[si] ;[BX] --> ICT
- mov [bx].ICT_hits,0
- add si,2 ;up to next ICT
- loop zap_hits2 ;till we've done all of them
-
- mov next_byte,offset trace_table
- sti ;interrupts OK now
- pop cx
- pop bx
- pop ax
- pop si
- ret
- zap_hits endp
- page
- ;*********************************************
- ;
- ; Handle main menu selection whose ASCII keypress is in AL.
- ;
- ; Returns: CARRY SET if we should loop back to main menu.
- ; CARRY CLEAR to exit.
- ;
- ;*********************************************
-
- do_main proc near
- push ax
- cmp al,'P' ;select printer?
- jnz do_main1 ;no
- call selprint ;yes, do it
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main1:
- cmp al,'S' ;select screen?
- jnz do_main2 ;no
- call selvideo ;yes, do it
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main2:
- cmp al,'T' ;Dump Traces?
- jnz do_main3 ;no
- call do_traces ;yes, do it
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main3:
- cmp al,'E' ;Enable ICT?
- jnz do_main4 ;no
- mov al,F_ENABLE ;yes, get bit value to set/clear
-
- do_main3b:
- call do_enable ;enable/disable F_ENABLE per AL
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main4:
- cmp al,'D' ;Disable ICT?
- jnz do_main5 ;no
- mov al,0 ;yes, get bit value to set/clear
- jmp do_main3b
-
- do_main5:
- cmp al,'L' ;List ICT's?
- jnz do_main6 ;no
- call disp_active ;yes, do it
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main6:
- cmp al,'C' ;Clear trace table?
- jnz do_main7 ;no
- call zap_hits ;yes, do it
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main7:
- cmp al,'Q' ;Quit?
- jnz do_main8 ;no
- clc ;"Exit" flag
- jmp short do_main9
-
- do_main8:
- cmp al,'F' ;F_FCB toggle?
- jnz do_main8B ;no
- call do_fcb ;yes, toggle something
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main8b:
-
- ; ------ Unknown selection
-
- stc ;"Loop back to main menu" flag
-
- do_main9:
- pop ax
- ret
- do_main endp
-
-
- ;**********************************************
- ;
- ; Pick ICT's with which to do something.
- ;
- ; This is called to select ICT for various operations.
- ;
- ; On entry, DX holds address of question (no CRLF's) to be asked.
- ;
- ; Returns: CARRY SET if user selected ABORT to cancel the caller's operation
- ;
- ; CARRY CLEAR if AL has been set to 8-bit pattern, with each
- ; bit from 0 to 7 representing an ICT (0-7) that was selected.
- ;
- ;**********************************************
-
- pick_ict proc near
- push bx
- push cx
- push dx
- mov byte ptr pick_map,0 ;init to nobody selected
-
- pick_ict1:
-
- ;
- ; Put up our selection menu
- ;
-
- call crlf
- pop dx ;display caller's question
- push dx
- call print_line
- mov dx,offset pick_menu ;put up our menu
- call print_line
-
- ;
- ; Fill in choices already made, as if he had typed them
- ;
-
- mov cx,8 ;# ICT's
- mov ah,byte ptr pick_map ;AH has bitmap
- mov al,'0' ;AL holds ASCII '0' - '7'
-
- pick_ict1b:
- test ah,1 ;Is this ICT selected?
- jz pick_ict1c ;no
- call print ;yes, show corresponding ASCII char
-
- pick_ict1c:
- inc al ;Bump ASCII char
- shr ah,1 ;get next bit to test
- loop pick_ict1b ;till done all 8
- call feed ;eject paper on printer
-
- pick_ict2:
-
- ;
- ; Get and handle next keypress
- ;
-
- call key
- cmp al,'0' ;ICT number?
- jb pick_ict3 ;no
- cmp al,'7'
- ja pick_ict3 ;no
- call print ;yes, echo it
-
- ;
- ; Convert this ASCII char to bitmap bit, and add to our map
- ;
-
- call bin_to_bit ;comes back in AL
- or byte ptr pick_map,al ;add this new bit into pattern
- jmp pick_ict2 ;go get next keypress
-
- pick_ict3:
- cmp al,'L' ;List ICT's?
- jnz pick_ict4 ;no
- call disp_active ;yes, show all active ICT's
- jmp pick_ict1 ;give our menu again
-
- pick_ict4:
- cmp al,'R' ;Restart?
- jnz pick_ict5 ;no
- mov byte ptr pick_map,0 ;yes, clear map
- jmp pick_ict1 ;give new menu
-
- pick_ict5:
- cmp al,'G' ;Go with choices?
- jnz pick_ict6 ;no
-
- pick_ict5b:
- mov al,byte ptr pick_map ;yes, get choices as bitmap
- clc ;tell caller to use it
- jmp short pick_ict9 ;exit
-
- pick_ict6:
- cmp al,0dh ;Carriage Return?
- jz pick_ict5b ;yes, same as "Go"
- cmp al,'A' ;Abort operation?
- jnz pick_ict7 ;no
-
- pick_ict6b:
- stc ;tell caller to abort
- jmp short pick_ict9 ;exit
-
- pick_ict7:
- cmp al,1bh ;ESCAPE?
- jz pick_ict6b ;yes, same as "Abort"
-
- ; ------ Unknown choice
-
- jmp pick_ict2 ;go get next keypress
-
- pick_ict9:
- pop dx
- pop cx
- pop bx
- ret
- pick_ict endp
-
- pick_menu db 0dh,0ah
- db "0-7 picks ICT (L)ist ICT's (A)bort (R)estart (G)o with choices"
- db 0dh,0ah,":$"
-
- pick_map db 0 ;bitmap of selected ICT's
-
-
- ;*********************************************
- ;
- ; Handle "Traces" main menu option
- ;
- ;*********************************************
-
- do_traces proc near
- push ax
- push dx
- mov dx,offset trace_menu ;put up our menu
- call print_line
- call feed ;extra CRLF's for printer
- call key ;get his selection
- cmp al,'A' ;dump All?
- jnz do_traces2 ;no
- mov al,0ffh ;yes, get bitmap for all ICT's
- jmp short do_traces7 ;dump 'em
-
- do_traces2:
- cmp al,'S' ;Selected ICT's?
- jnz do_traces9 ;no, so exit
- mov dx,offset trace_prompt ;point to question to be used
- call pick_ict ;get ICT's as bitmap in AL
- jc do_traces9 ;user wants to forget about it
-
- do_traces7:
-
- ;
- ; Do dump, with AL holding bitmap of ICT's that are to be included
- ;
-
- call dump_buf ;with AL already set
-
- do_traces9:
- pop dx
- pop ax
- ret
- do_traces endp
-
- trace_menu db 0dh,0ah
- db "Display (A)ll or (S)elected ICTs' traces:$"
- trace_prompt db "Pick ICT's whose traces are to be included in dump$"
-
-
- ;*********************************************
- ;
- ; Set or Clear F_ENABLE.
- ;
- ; On entry, AL holds bit value for F_ENABLE (i.e. - ON or OFF).
- ;
- ; This routine asks user for ICT's to be enabled or disabled.
- ;
- ;*********************************************
-
- do_enable proc near
- push si
- push dx
- push cx
- push bx
- push ax ;push him last so we can get to him
-
- mov dx,offset enable_prompt ;Assume "Enable"
- test al,F_ENABLE ;are we enabling?
- jnz do_enable1 ;yes, we have right message
- mov dx,offset disable_prompt ;Use "Disable" message
-
- do_enable1:
- call pick_ict ;get ICT's to be affected
- jc do_enable9 ;user wants to forget it
- mov byte ptr enable_map,al ;save bitmap of ICT's to be done
- xor si,si ;start with ICT #0
- mov cx,8 ;number of ICT's to look at
-
- do_enable2:
- test byte ptr enable_map,1 ;Should this ICT be done?
- jz do_enable5 ;no
- mov bx,ict_index[si] ;yes, point to ICT
- cli ;*** NO INTERRUPTS!!! ***
- pop ax ;get F_ENABLE value
- push ax
- and al,F_ENABLE ;isolate our bit
- mov ah,[bx].ICT_flags ;get current flags value
- and ah,F_ENABLE XOR 0ffh ;turn off our bit
- or ah,al ;set it per caller's desire
- mov [bx].ICT_flags,ah ;replace it in ICT
- STI ;*** INTERRUPTS OK NOW ***
-
- do_enable5:
- add si,2 ;up to next ICT
- shr byte ptr enable_map,1 ;get next ICT's bitmap bit to Bit 0
- loop do_enable2 ;till we've looked at all ICT's
-
- do_enable9:
- pop ax
- pop bx
- pop cx
- pop dx
- pop si
- ret
- do_enable endp
-
- enable_prompt db "Pick ICT's to have tracing ENABLED$"
- disable_prompt db "Pick ICT's to have tracing DISABLED$"
- enable_map db 0 ;bitmap of ICT's to be altered
-
-
-
-
- ;*********************************************
- ;
- ; Toggle F_FCB in some ICT's.
- ;
- ;*********************************************
-
- do_fcb proc near
- push si
- push dx
- push cx
- push bx
- push ax ;push him last so we can get to him
-
- mov dx,offset fcb_toggle
- call pick_ict ;get ICT's to be affected
- jc do_fcb9 ;user wants to forget it
- xor si,si ;start with ICT #0
- mov cx,8 ;number of ICT's to look at
-
- do_fcb2:
- test al,1 ;Should this ICT be done?
- jz do_fcb5 ;no
- mov bx,ict_index[si] ;yes, point to ICT
- xor [bx].ICT_flags,F_FCB ;toggle current setting
-
- do_fcb5:
- add si,2 ;up to next ICT
- shr al,1 ;get next ICT's bitmap bit to Bit 0
- loop do_fcb2 ;till we've looked at all ICT's
-
- do_fcb9:
- pop ax
- pop bx
- pop cx
- pop dx
- pop si
- ret
- do_fcb endp
-
- fcb_toggle db "Pick ICT's to have F_FCB toggled$"
-
- subttl Reporting Routines
- page
- ;**************************************************
- ;
- ; Dump trace buffer for ICT's represented by bitmap in AL.
- ;
- ; If bit n in AL is set, then ICT n's trace records are to be included
- ; in dump.
- ;
- ;**************************************************
-
-
- dump_buf proc near
- push di
- push si
- push dx
- push cx
- push bx
- push ax ;push bitmap last so that we can get to it
- xor di,di ;di is printed line counter
- mov si,offset trace_table ;start at front of buf
-
- dump_buf2:
- cmp si,next_byte ;done whole buffer?
- jae dump_buf9 ;yes, exit
-
- ;
- ; Let a keypress interrupt us
- ;
-
- mov ah,1 ;ROM BIOS "Check for keypress" func
- int 016h ;keypress present?
- jnz dump_buf9 ;yes, exit
-
- mov al,[si].B_type ;get ICT #
- call bin_to_bit ;convert to bitmap bit
- pop bx ;peek at caller's requested bitmap
- push bx
- and bl,al ;is this ICT included in caller's bitmap?
- jz dump_buf5 ;no, skip it
-
- ;
- ; See if it's time for title line
- ;
-
- test di,07h ;every 8 lines
- jnz dump_buf4 ;not time for title line
- mov dx,offset dump_title ;print title line
- call print_line
-
- dump_buf4:
- call dump_rec ;dump this record
- inc di ;bump # lines printed
-
- dump_buf5:
-
- ;
- ; Skip over this record, to next one. To do that, we need to know what
- ; type of record it is, so that we know how big a record
- ; we have to skip over.
- ;
-
- mov bl,[si].B_type ;get trace record type
- and bx,11110000b ;isolate type itself
- shr bx,1 ;develop type times 2
- shr bx,1
- shr bx,1
- add si,rec_sizes[bx] ;add record size to current pointer
- jmp dump_buf2 ;continue till buffer exhausted
-
- dump_buf9:
- pop ax
- pop bx
- pop cx
- pop dx
- pop si
- pop di
- ret
- dump_buf endp
-
- dump_title db 0dh,0ah
- db 0dh,0ah
- db "INT # AX BX CX DX ES DS SI DI BP SS SP CS:IP"
- db 0dh,0ah
- db "--- - ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---------$"
-
- ;***********************************************
- ;
- ; Given binary number (0-7) in AL, return bitmap in AL with corresponding
- ; bit (Bit 0 thru Bit 7) set.
- ;
- ; AH is zeroed.
- ;
- ;***********************************************
-
- bin_to_bit proc near
- mov ah,al ;AH is counter, from 7 to 0
- mov al,1 ;AL is bitmap, Bit 0 to Bit 7
- and ah,7 ;constrain input
- jz bin_to_bit9 ;binary was 0, so return with Bit 0 set
-
- bin_to_bit3:
- add al,al ;shift bitmap left 1 bit
- dec ah ;dec count by one
- jnz bin_to_bit3
-
- bin_to_bit9:
- ret
- bin_to_bit endp
-
- ;***********************************************
- ;
- ; Dump trace record at [SI]. This routine prints the common
- ; header information, then calls specific routines to expand
- ; details.
- ;
- ;***********************************************
-
- dump_rec proc near
- push si
- push dx
- push cx
- push bx
- push ax
-
- call crlf
- mov al,[si].B_int ;get Interrupt #
- call print_hex ;show interrupt #
- mov al,'H'
- call print
- mov al,' '
- call print
- mov al,[si].B_type ;get ICT #
- and al,7
- or al,'0' ;make into ASCII digit
- call print
- mov al,' '
- call print
- mov bl,[si].B_type ;get trace type
- and bx,11110000b ;isolate type of trace
- shr bx,1 ;develop type times 2
- shr bx,1
- shr bx,1
- mov bx,word ptr dump_table[bx]
- call bx ;call proper specific routine
- pop ax
- pop bx
- pop cx
- pop dx
- pop si
- ret
- dump_rec endp
-
- ;
- ; Table of routines to handle various record types
- ;
-
- dump_table label word
- dw offset dump_before ;record type 0 = BEFORE
- dw offset dump_after ;record type 1 = AFTER
- dw offset dump_fcb ;record type 2 = FCB
- dw offset dump_asciiz ;record type 3 = ASCIIZ
-
- ;***********************************************
- ;
- ; Dump BEFORE record at [SI]
- ;
- ;***********************************************
-
- dump_before proc near
- push si
- push dx
- push cx
- push bx
- push ax
- mov al,'B' ;Display "B" for BEFORE
- call print
- mov al,' ' ;plus blank after
- call print
- mov ax,[si].B_ax
- call print_wordb
- mov ax,[si].B_bx
- call print_wordb
- mov ax,[si].B_cx
- call print_wordb
- mov ax,[si].B_dx
- call print_wordb
- mov ax,[si].B_es
- call print_wordb
- mov ax,[si].B_ds
- call print_wordb
- mov ax,[si].B_si
- call print_wordb
- mov ax,[si].B_di
- call print_wordb
- mov ax,[si].B_bp
- call print_wordb
- mov ax,[si].B_ss
- call print_wordb
- mov ax,[si].B_sp
- call print_wordb
- mov dx,[si].B_cs
- mov ax,[si].B_ip
- call print_seg
-
- ;
- ; Try to interpret this BEFORE record, to make reading easier
- ;
-
- call interp
- pop ax
- pop bx
- pop cx
- pop dx
- pop si
- ret
- dump_before endp
-
- ;***********************************************
- ;
- ; Dump AFTER record at [SI]
- ;
- ;***********************************************
-
- dump_after proc near
- push si
- push dx
- push cx
- push bx
- push ax
- mov al,'A' ;Display "A" for AFTER
- call print
- mov al,' ' ;plus blank after
- call print
- mov ax,[si].A_ax
- call print_wordb
- mov ax,[si].A_bx
- call print_wordb
- mov ax,[si].A_cx
- call print_wordb
- mov ax,[si].A_dx
- call print_wordb
- mov ax,[si].A_es
- call print_wordb
- mov ax,[si].A_ds
- call print_wordb
- mov ax,[si].A_si
- call print_wordb
- mov ax,[si].A_di
- call print_wordb
- mov ax,[si].A_bp
- call print_wordb
-
- ;
- ; Now expand flags byte for clarity
- ;
-
- mov dx,[si].A_flags ;hold flags in DX
- mov si,offset dump_flags ;SI = next flag's name
- mov bx,0fd5h ;mask of valid bits in flags word
- mov cx,12 ;# bits to walk through
- cld ;forward!!!
-
- dump_after2:
- test bx,1 ;is this a valid flag bit?
- jz dump_after4 ;no, move to next one
- lodsb ;yes, get next name
- test dx,1 ;is bit set?
- jnz dump_after3 ;yes, use name
- mov al,' ' ;no, use blank
-
- dump_after3:
- call print ;print flag name or space
-
- dump_after4:
- shr dx,1 ;shift flags so next flag is in bit 0
- shr bx,1 ;ditto for mask
- loop dump_after2 ;till done all 12 bits
-
- pop ax
- pop bx
- pop cx
- pop dx
- pop si
- ret
- dump_after endp
-
- dump_flags db "CPAZSTIDO"
-
-
- ;***********************************************
- ;
- ; Dump FCB record at [SI]
- ;
- ;***********************************************
-
- dump_fcb proc near
- push si
- push dx
- push cx
- push bx
- push ax
- mov al,[si].FCB_drive ;display drive # as number
- mov byte ptr fcb_drv,al
- mov dx,offset fcb_line ;and put up rest of header
- call print_edit
- add si,3 ;skip to filename field
- mov cx,8 ;max # chars to display
- cld ;forward!!!
-
- dump_fcb2:
- lodsb ;get byte of filename
- cmp al,020h ;control char or blank?
- jbe dump_fcb3b ;yes, we're done with name
- call print ;no, display char as-is
- loop dump_fcb2 ;till 8 done or early exit
- jmp short dump_fcb4
-
- dump_fcb3: ;skip over rest of filename
- lodsb
-
- dump_fcb3b:
- loop dump_fcb3
-
- dump_fcb4: ;output extension too
- mov al,'.' ;seperate it with period
- call print
- mov cx,3 ;# extension bytes to print
-
- dump_fcb5:
- lodsb ;get byte of extension
- cmp al,020h ;control char?
- jb dump_fcb6 ;yes, skip it
- call print ;no, use as-is
-
- dump_fcb6:
- loop dump_fcb5
- pop ax
- pop bx
- pop cx
- pop dx
- pop si
- ret
- dump_fcb endp
-
-
- fcb_line label byte
- db "FCB Drive:"
- db Edit_Dec8
- fcb_drv db 0
- db " Filename: "
- db Edit_End
-
- ;***********************************************
- ;
- ; Dump ASCIIZ record at [SI]
- ;
- ;***********************************************
-
- dump_asciiz proc near
- push si
- push dx
- push cx
- push bx
- push ax
- mov dx,offset asciiz_line ;put up header
- call print_line
- add si,2 ;skip to start of ASCIIZ text
- mov cx,size ASCIIZ ;max # chars to display
- sub cx,2 ;(minus 2 for header)
- cld ;forward!!!
-
- dump_asciiz5:
- lodsb ;get byte of extension
- or al,al ;NUL terminator?
- jz dump_asciiz9 ;yes, exit
- cmp al,020h ;control char?
- jb dump_asciiz6 ;yes, skip it
- call print ;no, use as-is
-
- dump_asciiz6:
- loop dump_asciiz5
-
- dump_asciiz9:
- pop ax
- pop bx
- pop cx
- pop dx
- pop si
- ret
- dump_asciiz endp
-
-
- asciiz_line label byte
- db "ASCIIZ: $"
-
-
- ;*****************************************
- ;
- ; Display what we know about ICT # AL (0-7).
- ;
- ;*****************************************
-
- ict_dump proc near
- push dx
- push bx
- push ax
-
- and ax,7 ;edit ICT #
- mov bx,ax ;get ICT #
- shl bx,1
- mov bx,ict_index[bx] ;[BX] --> ICT itself
-
- or al,030h ;make ASCII digit for message
- mov byte ptr ict_msg1a,al ;insert it into message
- mov dx,offset ict_msg1 ;"ICT #n at ..."
- call print_line
-
- mov dx,ds ;display seg:offset of ICT
- mov ax,bx
- call print_seg
-
- mov dx,offset ict_ena ;show whether enabled or disabled
- test [bx].ICT_flags,F_ENABLE
- jnz ict_dump2 ;got right message
- mov dx,offset ict_dis ;get other message
-
- ict_dump2:
- call print_line ;display "ENABLED" or "DISABLED"
-
- mov dx,offset ict_msg2 ;"INT xxH "
- call print_line
- mov al,[bx].ICT_intnum ;display interrupt #
- call print_hex
-
- mov dx,offset ict_msg3 ;"AH range ll/hh"
- call print_line
- mov al,[bx].ICT_AH_lo ;display AH range lower limit
- call print_hex
- mov al,'/' ;add seperator
- call print
- mov al,[bx].ICT_AH_hi ;display AH range upper limit
- call print_hex
-
- mov al,'*' ;display '*' if FCB/ASCIIZ set
- test [bx].ICT_flags,F_FCB
- jnz ict_dump3 ;it's set
- mov al,' ' ;not set, so use blank
-
- ict_dump3:
- call print
-
- mov dx,offset ict_msg4 ;"Exit: RET/RET2/IRET"
- call print_line
- mov al,[bx].ICT_flags ;interpret exit type
- mov dx,offset ict_exit ;get to first 6-char message
- test al,F_RET
- jz ict_dump5 ;not this one
- call print_line
-
- ict_dump5:
- add dx,6 ;up to next 6-char exit name
- test al,F_RET2
- jz ict_dump6 ;not this one
- call print_line
-
- ict_dump6:
- add dx,6 ;up to next 6-char exit name
- test al,F_IRET
- jz ict_dump7 ;not this one
- call print_line
-
- ict_dump7:
- mov dx,offset ict_msg4a ;"Hits: "
- call print_line
- mov ax,[bx].ICT_hits
- call print_dec
-
- pop ax
- pop bx
- pop dx
- ret
-
- ict_msg1 db 0dh,0ah,"ICT#"
- ict_msg1a db "0 @ $"
- ict_msg2 db " INT $"
- ict_msg3 db "H AH:$"
- ict_msg4 db " Exit:$"
- ict_msg4a db "Hits: $"
- ict_exit db "RET $" ;6-char exit type names
- db "RET2 $"
- db "IRET $"
- ict_ena db " ENABLED $"
- ict_dis db " DISABLED$"
-
- ict_dump endp
-
-
- ;*********************************************
- ;
- ; Display all active ICT's
- ;
- ;*********************************************
-
- disp_active proc near
- push si
- push ax
- push bx
- push cx
-
- mov cx,8 ;Number of ICT's
- xor si,si ;start with # 0
-
- disp_active2:
- mov bx,ict_index[si] ;[BX] --> ICT
- test [bx].ICT_flags,F_ACTIVE ;Is this ICT active?
- jz disp_active5 ;no, skip it
- mov ax,si ;yes, develop ICT # 0-7
- shr ax,1
- call ict_dump ;display it
-
- disp_active5:
- add si,2 ;up to next ICT
- loop disp_active2 ;till we've done all of them
- pop cx
- pop bx
- pop ax
- pop si
- ret
- disp_active endp
-
- subttl Interpretation - Misc Routines
- page
- ;********************************************************************
- ;* *
- ;* This file contains the routines that interpret selected *
- ;* BEFORE trace records and print out sensible summaries of *
- ;* their meanings. This sure beats having to read a lotta hex *
- ;* function codes. *
- ;* *
- ;* The main routine - interp() - is called just after we've *
- ;* printed all of the trace record in hex. If this record is *
- ;* one that we know about, we should now print a one-line *
- ;* interpretation of the record. This is done via lower-level *
- ;* routines called by interp() per the INT in the record. *
- ;* *
- ;********************************************************************
-
-
- ;********************************************************************
- ;
- ; Interpret BEFORE trace record at [SI].
- ;
- ;********************************************************************
-
- interp proc near
- push bx
- push ax
- mov ah,[SI].B_int ;get INT type
- mov bx,offset interp_tab ;point to table of handlers
-
- interp2:
- cmp ah,[bx] ;does this handler go with this INT?
- jnz interp5 ;no
- mov bx,1[bx] ;yes, get handler's address
- call bx ;call that handler
- jmp interp9 ;exit
-
- interp5:
- add bx,3 ;up to next entry in table
- cmp bx,offset interp_end ;searched whole table yet?
- jb interp2 ;no, try next one
-
- interp9:
-
- pop ax
- pop bx
- ret
- interp endp
-
- ;
- ; Table of interpreters for various interrupts.
- ;
- ; Each entry is as follows:
- ;
- ; db <intnum> ;interrupt number
- ; dw offset <handler> ;address of handler to interpret this int's record
- ;
- ;
-
- interp_tab label byte
- db 013h ;INT 13h is Diskette I/O
- dw offset interp_13 ;handler for INT 13h
- db 021h ;INT 21h is DOS Function Handler
- dw offset interp_21 ;handler for INT 21h
- db 025h ;INT 025H is DOS ABSOLUTE DISK READ
- dw offset interp_25
- db 026h ;INT 026H is DOS ABSOLUTE DISK WRITE
- dw offset interp_25 ;uses same interpreter
- interp_end label byte ;end of table
-
- subttl Interpretation - INT 13 (Diskette I/O)
- page
- ;
- ; Tables used to interpret INT 13h
- ;
-
- Floppy_or_Hard db 0,"Floppy:",0
- db 080h,"Fixed:",080h
-
- Cyl_or_Track db 0,"Track:",0
- db 080h,"Cyl:",080h
-
- int13_functab label byte
- db 0,"Reset Disk",0
- db 1,"Read Status",0
- db 2,"Read to ES:BX",0
- db 3,"Write from ES:BX",0
- db 4,"Verify",0
- db 5,"Format Track per ES:BX",0
- db 6,"Format & Set Bad Sects",0
- db 7,"Format Drive from Track",0
- db 8,"Get Drive Params",0
- db 9,"Init Drive Params",0
- db 10,"Read Long",0
- db 11,"Write Long",0
- db 12,"Seek",0
- db 13,"Alt Disk Reset",0
- db 14,"Read Sect Buf",0
- db 15,"Write Sect Buf",0
- db 16,"Test Drive Ready",0
- db 17,"Recalibrate",0
- db 18,"Ram Diagnostic",0
- db 19,"Drive Diagnostic",0
- db 20,"Internal Diagnostic",0
- db 21,"Get Disk Type",0
- db 22,"Change Status",0
- db 23,"Set Disk Type",080h
-
- int13_line label byte
- db 0dh,0ah," "
- db Edit_Call
- int13_F_or_H db 0
- dw offset Floppy_or_Hard
- dw offset table_print
- db Edit_Dec8
- int13_drive db 0
- db " Head:"
- db Edit_Dec8
- int13_head db 0
- db " "
- db Edit_Call
- int13_C_or_T db 0
- dw offset Cyl_or_Track
- dw offset table_print
- db Edit_Dec16
- int13_cyl dw 0
- db " Sect:"
- db Edit_Dec8
- int13_sect db 0
- db " #Sects:"
- db Edit_Dec8
- int13_numsects db 0
- db " "
- db Edit_Call
- int13_func db 0
- dw offset int13_functab
- dw offset table_print
- db Edit_End
-
- ;**************************************************
- ;
- ; Interpret INT 13h BEFORE trace record at [SI]
- ;
- ;**************************************************
-
- interp_13 proc near
- push dx
- push cx
- push ax
- mov dx,[SI].B_dx ;get DX at time of INT
- mov al,dl ;Get drive #
- and al,080h ;isolate floppy/hard bit
- mov int13_F_or_H,al ;use it to select device name...
- mov int13_C_or_T,al ;...as well as cylinders/tracks
- and dl,07fh ;isolate drive #
- mov int13_drive,dl
- mov int13_head,dh ;store head #
- mov cx,[SI].B_cx ;get CX at time of INT
- xor ax,ax ;calc 10-bit cylinder #
- mov al,cl
- shl ax,1
- shl ax,1
- mov al,ch
- mov int13_cyl,ax ;save as word
- and cl,00111111b ;isolate sector #
- mov int13_sect,cl
- mov ax,[SI].B_ax ;get AX at time of INT
- mov int13_numsects,al
- mov int13_func,ah
- mov dx,offset int13_line ;now print edited line
- call print_edit
- pop ax
- pop cx
- pop dx
- ret
- interp_13 endp
-
- subttl Interpretation - INT 21h (DOS)
- page
- ;
- ; Tables used in interpreting INT 21h
- ;
-
- int21_functab label byte
- db 0,"Terminate program",0
- db 1,"Console input w/echo to AL",0
- db 2,"Display Output of DL",0
- db 3,"AUX input to AL",0
- db 4,"AUX output from DL",0
- db 5,"Printer output from DL",0
- db 6,"Input to AL (DL=0FFh) or Display DL",0
- db 7,"Raw keyboard input w/o echo to AL",0
- db 8,"Console input w/o echo to AL",0
- db 9,"Print string at DS:DX till '$'",0
- db 0ah,"Buffered console input to DS:DX",0
- db 0bh,"Set AL=0FFh if input ready, else AL=0",0
- db 0ch,"Clear buf and do function in AL",0
- db 0dh,"Reset disk",0
- db 0eh,"Select drive per DL (0=A)",0
- db 0fh,"Open file, FCB at DS:DX",0
- db 10h,"Close file, FCB at DS:DX",0
- db 11h,"Search for first per pattern FCB at DS:DX",0
- db 12h,"Search for next per pattern FCB at DS:DX",0
- db 13h,"Delete file per FCB at DS:DX",0
- db 14h,"Read sequential, FCB at DS:DX",0
- db 15h,"Write sequential, FCB at DS:DX",0
- db 16h,"Create file, FCB at DS:DX",0
- db 17h,"Rename file, special FCB at DS:DX",0
- db 19h,"Return current drive in AL (0=A)",0
- db 1ah,"Set DTA to DS:DX",0
- db 1bh,"Get FAT info for default drive",0
- db 1ch,"Get FAT info for drive DL (0=default)",0
- db 21h,"Random Read, FCB at DS:DX",0
- db 22h,"Random Write, FCB at DS:DX",0
- db 23h,"Set file size per FCB pattern at DS:DX",0
- db 24h,"Set random rec field in FCB at DS:DX",0
- db 25h,"Set Interrupt <AL> vector to DS:DX",0
- db 26h,"Create new segment at <DX>:0000",0
- db 27h,"Random Read of <CX> records, FCB at DS:DX",0
- db 28h,"Random Write of <CX> records, FCB at DS:DX",0
- db 29h,"Parse filename at DS:SI into FCB at ES:DI",0
- db 2ah,"Get year to CX, month to DH, day to DL",0
- db 2bh,"Set year to CX, month to DH, day to DL",0
- db 2ch,"Get CH=hours CL=mins DH=secs DL=tenths",0
- db 2dh,"Set hours=CH mins=CL secs=DH tenths=DL",0
- db 2eh,"IFF DL=0 then set VERIFY per AL",0
- db 2fh,"Get DTA to ES:BX",0
- db 30h,"Get DOS version to AL (major), AH (minor)",0
- db 31h,"Term/stay resident, DX=# para's AL=exit code",0
- db 33h,"Request (AL=0) or set (AL=1,DL=value) BREAK value",0
- db 34h,"Set ES:BX to DOS 'in-use' flag",0
- db 35h,"Set ES:BX to vector for INT # <AL>",0
- db 36h,"Get disk space for drive DL (0=default)",0
- db 38h,"Return country info to DS:DX",0
- db 39h,"Create directory per ASCIIZ at DS:DX",0
- db 3ah,"Remove directory per ASCIIZ at DS:DX",0
- db 3bh,"Change directory to ASCIIZ at DS:DX",0
- db 3ch,"Create file per ASCIIZ at DS:DX, attrib <CX>",0
- db 3dh,"Open file per ASCIIZ at DS:DX, access <AL>",0
- db 3eh,"Close file handle <BX>",0
- db 3fh,"Read <CX> bytes from file handle <BX> to DS:DX",0
- db 40h,"Write <CX> bytes from DS:DX to file handle <BX>",0
- db 41h,"Delete file per ASCIIZ at DS:DX",0
- db 42h,"LSEEK file handle <BX> <CX:DX> bytes, method <AL>",0
- db 43h,"Set (AL=1, CX=value) or get (AL=0) attrib for ASCIIZ at DS:DX",0
- db 44h,"IOCTL for file handle <BX>, func <AL>",0
- db 45h,"DUP file handle <BX> into <AX>",0
- db 46h,"Force DUP of handle <BX> into handle <CX>",0
- db 47h,"Get cur dir for drive <DL> (0=default) to DS:SI",0
- db 48h,"Allocate <BX> paragraphs, address to AX",0
- db 49h,"Free block starting at <ES>",0
- db 4ah,"Modify segment <ES> to be <BX> para's in size",0
- db 4bh,"EXEC file at ASCIIZ DS:DX, func <AL>",0
- db 4ch,"Terminate with exit code <AL>",0
- db 4dh,"Get EXIT return code to AX",0
- db 4eh,"Find first per ASCIIZ at DS:DX and attrib <CX>",0
- db 4fh,"Find next per current DTA",0
- db 54h,"Get VERIFY state to AL",0
- db 56h,"Rename filename at ASCIIZ DS:DX to ASCIIZ at ES:DI",0
- db 57h,"Get (AL=0) or set (AL=1) date/time for file handle <BX>",0
- db 59h,"Get extended error code",0
- db 5ah,"Create temp file per ASCIIZ DS:DX and attrib <CX>",0
- db 5bh,"Create new file per ASCIIZ DS:DX and attrib <CX>",0
- db 5ch,"Lock (AL=0) or unlock (AL=1) file handle <BX>",0
- db 62h,"Get PSP segment address to BX",080h
-
- int21_line label byte
- db 0dh,0ah," DOS: "
- db Edit_Call
- int21_func db 0
- dw offset int21_functab
- dw offset table_print
- db Edit_End
-
- ;**************************************************
- ;
- ; Interpret INT 21h BEFORE trace record at [SI]
- ;
- ;**************************************************
-
- interp_21 proc near
- push dx
- push ax
- mov ax,[SI].B_ax ;get AX at time of int
- mov byte ptr int21_func,ah ;use it to select function
- mov dx,offset int21_line
- call print_edit
- pop ax
- pop dx
- ret
- interp_21 endp
-
- subttl Interpretation - INT 25h and 26h (Absolute disk I/O)
- page
- ;
- ; Tables used to interpret INT's 25h and 26h
- ;
-
- int25_functab label byte
- db 025h,"Read",0
- db 026h,"Write",080h
-
- int25_line label byte
- db 0dh,0ah," DOS Absolute "
- db Edit_Call
- int25_func db 0
- dw offset int25_functab
- dw offset table_print
- db " Drive:"
- db Edit_Dec8
- int25_drv db 0
- db " Sector:"
- db Edit_Dec16
- int25_sect dw 0
- db " #Sectors:"
- db Edit_Dec16
- int25_numsects dw 0
- db " Buf "
- db Edit_Word
- int25_seg dw 0
- db ":"
- db Edit_Word
- int25_off dw 0
- db Edit_End
-
- ;**************************************************
- ;
- ; Interpret INT 25h or INT 26h BEFORE trace record at [SI]
- ;
- ;**************************************************
-
- interp_25 proc near
- push dx
- push ax
- mov al,[SI].B_int ;get INT that was done (25h or 26h)
- mov int25_func,al ;move to printline
- mov ax,[SI].B_ax ;get drive # from AL
- mov int25_drv,al ;move to printline
- mov ax,[SI].B_dx ;get starting sector # from DX
- mov int25_sect,ax ;move to printline
- mov ax,[SI].B_cx ;get # sectors from CX
- mov int25_numsects,ax ;move to printline
- mov ax,[SI].B_ds ;get buffer segment from DS
- mov int25_seg,ax ;move to printline
- mov ax,[SI].B_bx ;get buffer offset from BX
- mov int25_off,ax ;move to printline
- mov dx,offset int25_line ;now print edited line
- call print_edit
- pop ax
- pop dx
- ret
- interp_25 endp
-
- subttl Periscope Interrupt Interface
- page
-
- ;*****************************************
- ;
- ; This is the interrupt handler use by Periscope to access this code.
- ; It may also be called by SHIFT-PrtSc.
- ;
- ; On entry, AH contains function:
- ;
- ; 1 - 8: User Breakpoint checks (BU 1 thru BU 8, then GT)
- ; 9 - FFh: User exits (/U 9 thru /U FFh)
- ; 0FFh: Called by PrtSc
- ;
- ;*****************************************
-
- db "PS" ;sentinel that Periscope checks for
- periscope proc far
-
- ;
- ; First, make very sure that we aren't being re-entered!!! This would
- ; wipe out our stack which is already in use.
- ;
-
- cli
- test cs:stack_inuse,0ffh
- jz periscope2 ;it's ok
-
- periscope1:
-
- mov al,0ffh ;tell Periscope "No Break, No Command to be executed"
- iret ;busy, call back later
-
- periscope2:
-
- ;
- ; If we've been entered via Periscope User Break function (during single-stepping,
- ; with BU 1 thru BU 8 in effect), then exit immediately. Things are slow
- ; enough without us being executed when we have no Breakpoint checking to do.
- ;
-
- cmp ah,9 ;BU 1 thru BU 8?
- jb periscope1 ;yes, exit
-
-
- ;
- ; On entry to this periscope int, we ought to save everything but AX,
- ; and switch to our own stack. Periscope itself doesn't require this,
- ; but the PrtSc routine assumes it.
- ;
-
- mov cs:stack_inuse,0ffh ;mark our stack busy
- mov cs:save_ss,ss
- mov cs:save_sp,sp
- mov ss,cs:our_cs
- mov sp,offset our_tos
- push cs:save_ss ;save old stack stuff for later
- push cs:save_sp
- push bx
- push cx
- push dx
- push si
- push di
- push es
- push ds
- push bp
- mov ds,cs:our_cs ;set DS to us for assume ds:code
- sti
-
- ;
- ; Give user stats about trace buffer size
- ;
-
- mov ax,offset last_byte ;get # free bytes
- sub ax,next_byte
- mov word ptr size_freeb,ax
- mov dx,offset size_msg
- call print_edit
-
- periscope_menu:
-
- ;
- ; Now display menu and get his selection, until we are to exit
- ;
-
- mov dx,offset mainmenu
- call print_line ;put up main menu
- call feed ;extra CRLF's for printer
- call key ;get keypress
- call do_main ;process it
- jc periscope_menu ;we are to loop back
- mov dx,offset shadows ;give him exit message
- call print_line
-
-
- periscope_exit:
-
- ;
- ; Restore regs and original stack. AX is already set to return result.
- ;
-
- cli
- pop bp
- pop ds
- pop es
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop cs:save_sp ;restore original stack
- pop cs:save_ss
- mov ss,cs:save_ss
- mov sp,cs:save_sp
- mov cs:stack_inuse,0 ;mark our stack not busy
- iret
- periscope endp
-
- mainmenu db 0dh,0ah
- db "(P)rinter (S)creen (E)nable (D)isable (F)CB (T)races (L)ist (C)lear (Q)uit$"
-
- shadows db 0dh,0ah
- db "Back... to the shadows... AGAIN!"
- db 0dh,0ah,"$"
-
- size_msg label byte
- db 0dh,0ah
- db "TraceBuf Bytes:"
- db Edit_Dec16
- dw trace_size
- db " Free Bytes:"
- db Edit_Dec16
- size_freeb dw 0
- db Edit_End
-
- subttl INT 05 (SHIFT-PrtSc) Handler
- page
- ;**************************************************
- ;
- ; This is another way (besides Periscope) to talk to the tracer, and
- ; get it to report what it's found. This is not as clean a way as
- ; via Periscope, but it beats nothing if the Periscope board isn't in
- ; the system.
- ;
- ; This routine just calls the Periscope interrupt handler.
- ;
- ;**************************************************
-
- if prt_scr
-
- PrtSc proc far
- cli
- push es
- push ax
- mov ax,050h ;set ES to 0050:0000
- mov es,ax ;(the print-screen control byte)
- cmp byte ptr es:[0],1 ;are we busy with previous request?
- jz PrtSc_exit ;yes, don't do anything
- mov byte ptr es:[0],1 ;no, mark us busy now
- mov ah,0ffh ;call Periscope INT with special arg
- int peri_int
- mov byte ptr es:[0],0 ;mark us not busy now
-
- PrtSc_exit:
- pop ax
- pop es
- iret
- Prtsc endp
-
- endif
-
- subttl Startup (init) code
- page
-
- ;********************************************************
- ;
- ; Startup code, which installs us in memory and sets up interrupts
- ; to be handled.
- ;
- ;********************************************************
-
- init:
- mov our_cs,cs ;save for handlers' use
- mov test_cs,cs ;start normalized CS for testing
- mov ax,offset init ;include all of resident part in it
- mov cl,4
- shr ax,cl
- add test_cs,ax ;done normalizing it
- mov dx,offset copyright
- mov ah,9
- int 021h
-
- ;
- ; Get printer base I/O address for use later
- ;
-
- mov ax,040h ;point to parallel table at 0040:0008
- mov es,ax
- mov dx,es:[8] ;get LPT1's base address
- mov prt_base,dx ;save it
- or dx,dx ;is there an LPT1?
- jnz init2 ;yes, move on
- mov dx,offset no_printer ;no, give warning message...
- call selvideo ;...after switching to video
- call print_line
-
- init2:
-
- ;
- ; Init proper I/O mode
- ;
-
- if use_prt
- call selprint
- else
- call selvideo
- endif
-
- ;
- ; Install Periscope access interrupt # 'peri_int'
- ;
-
- mov al,peri_int ;INT # being installed
- mov ah,025h ;DOS "Install Int Vector" func
- mov dx,offset periscope ;DS:DX = handler for this INT
- int 021h
-
- ;
- ; Install SHIFT-PrtSc interrupt
- ;
-
- if prt_scr
- mov al,5 ;INT # being installed
- mov ah,025h ;DOS "Install Int Vector" func
- mov dx,offset PrtSc ;DS:DX = handler for this INT
- int 021h
- endif
-
- ;
- ; Install interrupt vectors for any active ICT's
- ;
-
- mov cx,8 ;number of ICT's
- xor si,si ;Start with ICT # 0
-
- init5:
- mov bx,ict_index[si] ;get pointer to an ICT
- mov al,[bx].ICT_flags ;get flags to AL
- test al,F_ACTIVE ;is this ICT active?
- jz init10 ;no, move on to next one
-
- ; ------- Validate type of interrupt exit
-
- and al,F_RET+F_RET2+F_IRET
- cmp al,F_RET
- jz init6 ;this one's legal
- cmp al,F_RET2
- jz init6 ;this one's legal
- cmp al,F_IRET
- jz init6 ;this one's legal
- mov dx,offset bad_exit ;bad field, give error message
-
- init5b:
-
- ;
- ; Print error message at DS:DX and mark ICT de-activated
- ;
-
- push dx ;save error message text
- mov ax,si ;get ICT # for error message
- shr ax,1
- and al,7 ;(just in case)
- or al,'0' ;make into ASCII digit
- mov err_ict,al ;move into error header
- mov dx,offset err_msg ;print error header first
- call print_line
- pop dx ;recover error message itself
- call print_line ;display it
- xor [bx].ICT_flags,F_ACTIVE ;de-activate this ICT
- jmp short init10 ;goto next ICT
-
- init6:
- mov al,[bx].ICT_intnum ;get int number to AL
-
- if prt_scr
- cmp al,5 ;trying to trace INT 5?
- jnz init6b ;no, it's all right
- mov dx,offset two_prtscrs ;yes, give error message
- jmp init5b
-
- init6b:
- endif
-
- mov ah,035h ;get current vector for this INT
- push bx ;(save ICT pointer!!!)
- int 021h
- mov dx,bx ;put vector's offset somewhere safe
- pop bx ;(restore ICT pointer!!!)
-
- mov word ptr [bx].ICT_orig_hndlr,dx
- mov word ptr [bx].ICT_orig_hndlr+2,es
-
- mov dx,hndlr_index[si] ;DS:DX = new vector for this INT
- mov ah,025h ;tell DOS to install it
- int 021h ;(intnum still in AL)
-
- init10:
- add si,2 ;up to next ICT
- loop init5 ;till done all ICT's
-
- ;
- ; List final ICT's
- ;
-
- mov dx,offset final_msg
- call print_line
- call disp_active ;display all active ICT's
- call crlf
-
- ;
- ; Terminate and stay resident
- ;
-
- mov dx,offset intro_msg ;give him intro message
- call print_line
- mov al,peri_int
- call print_hex
- call crlf
- call feed ;extra CRLF's for printer
- mov dx,offset init
- int 027h
-
- ;********************************************************
- ;
- ; Startup messages (lost once we're resident)
- ;
- ;********************************************************
-
- copyright db 0dh,0ah
- db "TRACE - Interrupt Tracer version 1.2 2/26/86"
- db 0dh,0ah
- db 0dh,0ah
- db "Written by Joan Riff for:"
- db 0dh,0ah
- db "Computerwise Consulting Services P.O. Box 813, McLean VA 22101 (703) 280-2809"
- db 0dh,0ah
- db 0dh,0ah
- db "Placed in the public domain. There ain't one person in a thousand qualified to"
- db 0dh,0ah
- db "understand or use this thing, so why charge for it?"
- db 0dh,0ah,"$"
-
-
- intro_msg db 0dh,0ah
- db 0dh,0ah
- db "Trace is now resident."
- db 0dh,0ah
- db "Use '/U 9' Periscope command"
- if prt_scr
- db " (or SHIFT-PrtSc)"
- endif
- db " for access."
- db 0dh,0ah
- db "When you run Periscope, include command-line arg /I:$"
- bad_exit db "has a bad Exit field. ICT deactivated.$"
- two_prtscrs db "overlays SHIFT-PrtSc. ICT deactivated.$"
- no_printer db 0dh,0ah,"*** Warning: LPT1 not available$"
- err_msg db 0dh,0ah,"*** ICT #"
- err_ict db "0 $"
- final_msg db 0dh,0ah
- db 0dh,0ah,"Final ICT's:",0dh,0ah,"$"
-
- code ends
- end start
-